#include "theater.h"
#include "synch.h"
#include "system.h"
unsigned int movie_laststate=MOVIE_READY;

//Print all earnings made so far by the theater
void theaterPrint()
{
	/*
    int totalcus_number=0;
    int total_popcorn=0;
    int total_soda=0;
    for(int i=0; i<numTicketClerks; i++)
    {
        DBGPRINT(DEBUG_TRACE,"ticket clerk %d sold %d tickets\n",i,ticketclrk_totalticksnum[i]);
        totalcus_number+=ticketclrk_totalticksnum[i];
    }
    for(int i=0; i<numConcessionClerks; i++)
    {
        DBGPRINT(DEBUG_TRACE,"food clerk %d sold %d popcorn , and %d soda\n",i,popcorn_totalnum[i],soda_totalnum[i]);
        total_popcorn+=popcorn_totalnum[i];
        total_soda+=soda_totalnum[i];
    }
    DBGPRINT(DEBUG_TRACE,"total tickets %d sold, money %d\n",totalcus_number,TICKET_PRICE*totalcus_number);
    DBGPRINT(DEBUG_TRACE,"total popcorn %d sold, soda %d, money %d\n",total_popcorn,total_soda,total_popcorn*POPCORN_PRICE+total_soda*SODA_PRICE);
	*/
	
	printf("Total money made by office = [%d]\n", all_ticketmoney + all_foodmoney);
}

//the manager told the ticketclerk to work
//if find a clerk need to break, return the workno, otherwise return -1
int  CheckLineBreak(unsigned int line[],unsigned  int lineState[],int size)
{
    int i,j,k;
    int line_mayneedoff;
    int flag=0;
    //step a: to find out if a line is empty
    for( i=0,  j=0,  k=0; i<size; i++)
    {
        if(ON_WORK==lineState[i])
        {
            if(0==line[i])
            {
                k++;
                line_mayneedoff=i;
            }
            j++;
        }
    }
    if((k>=1)&&(j>1))//there is a free line and the total working ticket clerk is more than one
        flag=1;
    // DBGPRINT(DEBUG_INFO, "%d lines is working, %d is empty, flag is %d\n ", j,k,flag);
    //step b: if there are two lines that less than 3
    if(0==flag)//now, we only do that if we do not need off any clerks
    {
        for( i=0, j=0, k=0; i<size; i++)
        {
            if(ON_WORK==lineState[i])
            {
                if(line[i]<3)
                {
                    k++;
                    line_mayneedoff=i;
                }
                j++;
            }
        }
        if(k>=2&&j>2)//there is a free line and the total working ticket clerk is more than one
            flag=1;
    }
    //  DBGPRINT(DEBUG_INFO, "%d lines is working, %d is less than 3, flag is %d\n ", j,k,flag);
    //at last if we need to break a ticket clerk, we need to find we break it or not
    if(1==flag)
    {
        if(rand()%5==0) //rand to know wheter to break it or not
        {
            //    DBGPRINT(DEBUG_INFO,"we are going to break line %d\n",line_mayneedoff);
            return line_mayneedoff;
        }
    }
    return -1;
}
int checkLineWake(unsigned int line[],unsigned  int lineState[],int size)
{
    int i,j,k;
    for( i=0, j=0,k=-1; i<size; i++)
    {
        if(ON_WORK==lineState[i])
        {
            if(line[i]>5)
            {
                k=i;
            }
            j++;
        }
    }
    if(-1!=k&&j<(size-1))
        return k;
    else
        return -1;

}

void sendMoneyToManagerFromTicketClerk(int clerkNumber, int moneyAmount)
{
	all_ticketmoney += moneyAmount;
	printf("Manager collected [%d] from TicketClerk[%d].\n", moneyAmount, clerkNumber);
	theaterPrint();
}

void sendMoneyToManagerFromConcessionClerk(int clerkNumber, int moneyAmount)
{
	all_foodmoney += moneyAmount;
	printf("Manager collected [%d] from ConcessionClerk[%d].\n", moneyAmount, clerkNumber);
	theaterPrint();
}

void Manager_startWork(unsigned int manager_workno)
{
    DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to work\n",manager_workno);
    while(1)
    {
        //step 1: check the tickerclerk line
        int no=-1;
        //step a:
        ticketClerkLineLock->Acquire();
        //  DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to check ticketclerk line beak\n",manager_workno);
        no=CheckLineBreak(ticketclrk_cus_count, ticketclrk_off, numTicketClerks);
        if(-1!=no)  //new we need to break the lucky clerk
        {
            //step 1: if the clerk is busy now, we just set his flag to off, and after this customer,
            //he would be off
			printf("Manager has told TicketClerk [%d] to go on break.\n", no);
            ticketClerkMsgLock[no]->Acquire();
            ticketclrk_off[no]=OFF_WORK;
            ticketclerkMsg_cv[no]->Signal(ticketClerkMsgLock[no]);
            ticketClerkMsgLock[no]->Release();
        }
        else     //only when we do not need off a clerk
        {
            //    DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to check ticketclerk line full\n",manager_workno);
            int line=checkLineWake(ticketclrk_cus_count, ticketclrk_off, numTicketClerks);
            if(-1!=line)
            {
                for(int i=0; i<numTicketClerks; i++)
                {
                    if(OFF_WORK==ticketclrk_off[i])
                    {
                        ticketClerkMsgLock[i]->Acquire();
                        //            DBGPRINT(DEBUG_TRACE, "we need to wake up the ticket clerk %d \n", i);
                        ticketclrk_off[i]=ON_WORK;
                        ticketclerkMsg_cv[i]->Signal(ticketClerkMsgLock[i]);
                        ticketClerkMsgLock[i]->Release();
                        break;
                    }
                }
                //tell the customer to pick a new line:

                ticketClerkMsgLock[line]->Acquire();
                //            DBGPRINT(DEBUG_TRACE, "we need to wake up the ticket clerk %d \n", i);
                ticketclrk_addNewline[line]=ADD_NEWLINE;
                ticketclerkMsg_cv[line]->Signal(ticketClerkMsgLock[line]);
                ticketClerkMsgLock[line]->Release();
            }
        }
        ticketClerkLineLock->Release();
        //step 2: check the concession clerk line
        no=-1;
        //step a:
        concessClerkLineLock->Acquire();
        //    DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to check concessClerkLineLock line beak\n",manager_workno);
        no=CheckLineBreak(concessclrk_cus_count, concessclrk_off, numConcessionClerks);
        if(-1!=no) //new we need to break the lucky clerk
        {
                //to break
				printf("Manager has told ConcessionClerk [%d] to go on break.\n", no);
                concessClerkMsgLock[no]->Acquire();
                concessclrk_off[no]=OFF_WORK;
                concessclerkMsg_cv[no]->Signal(concessClerkMsgLock[no]);
                concessClerkMsgLock[no]->Release();
        }//step b: if there are more than five customers in a line, wake up a off clerk
        else {
            int line;
            line=checkLineWake(concessclrk_cus_count, concessclrk_off, numConcessionClerks);
            if(-1!=line)
            {
                for(int i=0; i<numConcessionClerks; i++)
                {
                    if(OFF_WORK==concessclrk_off[i])
                    {
                        concessClerkMsgLock[i]->Acquire();
                        //            DBGPRINT(DEBUG_TRACE, "we need to wake up the ticket clerk %d \n", i);
                        concessclrk_off[i]=ON_WORK;
                        concessclerkMsg_cv[i]->Signal(concessClerkMsgLock[i]);
                        concessClerkMsgLock[i]->Release();
                        break;
                    }
                }
                //tell the customer to pick a new line:

                concessClerkMsgLock[line]->Acquire();
                //            DBGPRINT(DEBUG_TRACE, "we need to wake up the ticket clerk %d \n", i);
                foodclrk_addNewline[line]=ADD_NEWLINE;
                concessclerkMsg_cv[line]->Signal(concessClerkMsgLock[line]);
                concessClerkMsgLock[line]->Release();
            }
        }
        concessClerkLineLock->Release();
        //step 3: check the ticket takers line
        no=-1;
           //step a:
          ticketTakerLineLock->Acquire();
        //     DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to check tickettaker line beak\n",manager_workno);
            no=CheckLineBreak(ticketTaker_cus_count, ticketTaker_off, numTicketTakers);
            if(-1!=no) //new we need to break the lucky clerk
            {
                //step 1: if the clerk is busy now, we just set his flag to off, and after this customer,
                //he would be off
				printf("Manager has told TicketTaker [%d] to go on break.\n", no);
                     DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to break taker\n",no);
                    ticketTakerMsgLock[no]->Acquire();
                          DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to break taker\n",no);
                    ticketTaker_off[no]=OFF_WORK;
                    ticketTakerMsg_cv[no]->Signal(ticketTakerMsgLock[no]);
                          DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to break taker\n",no);
                    ticketTakerMsgLock[no]->Release();
            }
            //step b: if there are more than five customers in a line, wake up a off clerk
            else//only when we do not need off a clerk
            {
          //      DBGPRINT(DEBUG_TRACE,"ticket manager %d is going to check concessClerkLineLock line full\n",manager_workno);
              //  if(checkLineWake(ticketTaker_cus_count, ticketTaker_off, numTicketTakers))
               int line=checkLineWake(ticketTaker_cus_count, ticketTaker_off, numTicketTakers);
                    if(-1!=line)
                {
                    for(int i=0; i<numTicketTakers; i++)
                    {
                        if(OFF_WORK==ticketTaker_off[i])
                        {
                            ticketTakerMsgLock[i]->Acquire();
                //            DBGPRINT(DEBUG_TRACE, "we need to wake up the ticket clerk %d \n", i);
                            ticketTakerMsgLock[i]=ON_WORK;
                            ticketTakerMsg_cv[i]->Signal(ticketTakerMsgLock[i]);
                            ticketTakerMsgLock[i]->Release();
                            break;
                        }
                    }
                    //tell the customer to pick a new line:

                            ticketTakerMsgLock[line]->Acquire();
                //            DBGPRINT(DEBUG_TRACE, "we need to wake up the ticket clerk %d \n", i);
                            tickettaker_addNewline[line]=ADD_NEWLINE;
                              ticketTakerMsg_cv[line]->Signal(ticketTakerMsgLock[line]);
                             ticketTakerMsgLock[line]->Release();
                  }
            }
            ticketTakerLineLock->Release();
        //step 4: decide to start a movie or not if the movie is not playing right now*/
        //step 1: to check the state of the movie, if the is playing, we could not allow the ticket taker take cusomers in
        if(movie_state!=movie_laststate)
        {
            if(MOVIE_PLAYING==movie_state)
            {
				printf("Manager is telling the MovieTechnnician to start the movie.\n");
                DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
                //  ticTkr_ready=NOTREADYTOTAKETIC;
                movie_laststate=MOVIE_PLAYING;
                DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
                //    DBGPRINT(DEBUG_TRACE, "manager tell the ticket taker that the movie is on, you could rest \n");
            }
            else if(MOVIE_OVER==movie_state)
            {
                DBGPRINT(DEBUG_INFO,"set NOTREADYTOTAKETIC \n");
                // if(rand()%2==0)
                {
                    movie_stateLock->Acquire();
                    DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
                    movie_state=MOVIE_READY;
                    DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);

                    movieTechMsgLock->Acquire();
                    movieTechMsg_cv->Signal(movieTechMsgLock);
                    movieTechMsgLock->Release();
                    movie_stateLock->Release();

                    DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
                    movie_laststate=MOVIE_OVER;
                    DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
                }
                //right now, we need to notify the ticket takers to take the ticket
                //     DBGPRINT(DEBUG_TRACE, "manager tell the ticket taker that the movie is over, you could take tickets \n");
                for(int i=0; i<numTicketTakers; i++)
                {
                    if(OFF_WORK!=ticketTaker_off[i])
                    {
                        ticketTakerMsgLock[i]->Acquire();
                        DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
                        ticTkr_ready=READYTOTAKETIC;
                        DBGPRINT(DEBUG_INFO,"try to wake up %d ticket taker\n",i);
                        ticketTakerMsg_cv[i]->Signal(ticketTakerMsgLock[i]);
                        DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
                        ticketTakerMsgLock[i]->Release();
                    }
                }
            }
            else if(MOVIE_READY==movie_state)
            {
                // DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
            }
        }
        // DBGPRINT(DEBUG_INFO,"set movie state %d \n",movie_state);
        //Simulate the time it takes the movie to finish
        for(int i=0; i<10; i++)
            currentThread->Yield();
		//Check to finish execution of program if no customers are left
    }
}

